const path = require('path') // nodejs核心模块，专门用来处理路径问题
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin");
// nodejs核心模块，直接使用
const os = require("os");
// cpu核数
const threads = os.cpus().length;
const TerserPlugin = require("terser-webpack-plugin");

const getStyleLoader = (pre) => {
  return [
    MiniCssExtractPlugin.loader, // 将js中css通过创建style标签添加html文件中生效
    'css-loader', // 将css资源编译成commonjs的模块到js中
    { 
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: [
            "postcss-preset-env", // 能解决大多数样式兼容性问题
          ],
        },
      },
    },
    pre
  ].filter(Boolean)
}

module.exports = {
  // 入口
  entry: './src/main.js', // 相对路径
  // 输出
  output: {
    // 输出路径
    path: path.resolve(__dirname, '../dist'), // 绝对路径, __dirname nodejs的变量，代表当前文件的文件夹目录
    // 入口文件打包输出文件名
    filename: 'js/main.js',
    // 自动清空上次打包结果
    // 原理：在打包前，将path中配置的地址【本项目中指dist】整个目录清空，再进行打包
    clean: true
  },
  // 加载器
  module: {
    rules: [
      {
        oneOf: [
          // loader的配置
          {
            test: /\.css$/, // 只检测.css文件
            // loader: 'xxx', // loader只能使用一个loader，use可以使用多个loader
            use: getStyleLoader()
          },
          {
            test: /\.less$/, // 只检测.less文件
            use: getStyleLoader('less-loader')
          },
          //#region 
          // {
          //     test: /\.s[ac]ss$/, // 只检测.sass/.scss文件
          //     use: [ // 执行顺序：从右到左（从下至上）
          //         MiniCssExtractPlugin.loader, // 将js中css通过创建style标签添加html文件中生效
          //         'css-loader', // 将css资源编译成commonjs的模块到js中
          //         'sass-loader' // 将sass编译为css文件
          //     ]
          // },
          // {
          //     test: /\.styl$/, // 只检测.styl文件
          //     use: [ // 执行顺序：从右到左（从下至上）
          //         MiniCssExtractPlugin.loader, // 将js中css通过创建style标签添加html文件中生效
          //         'css-loader', // 将css资源编译成commonjs的模块到js中
          //         'stylus-loader' // 将stylus编译为css文件
          //     ]
          // },
          //#endregion
          {
            test: /\.(png|jpe?g|gif|webp|svg)$/, 
            type: 'asset', // 有可能会转成base64
            parser: { // 转base64条件配置
              dataUrlCondition: {
                // 小于10kb的图片转base64
                // 有点：减少请求数量，缺点：体积会更大
                maxSize: 10 * 1024, // 10kb
              }
            },
            generator: {
              // 输出图片名称
              // filename: 'static/images/[hash][ext][query]'
              filename: 'static/images/[hash:10][ext][query]'// [hash:10] 限制文件长度最多为十位，hash值取前十位
            }
          },
          {
            test: /\.(ttf|woff2?|mp3|mp4|avi)$/, 
            type: 'asset/resource', // 不会转成base64
            generator: {
              // 输出名称
              filename: 'static/media/[hash:10][ext][query]'// [hash:10] 限制文件长度最多为十位，hash值取前十位
            }
          },
          {
            test: /\.js$/,
            exclude: /node_modules/, // 排除node_modules代码不编译
            use: [
              {
                loader: 'thread-loader', // 开启多进程
                options: {
                  works: threads // 进程数量
                }
              },
              {
                loader: "babel-loader",
                options: { // 写在babel.config.js中
                  // presets: ['@babel/preset-env']
                  cacheDirectory: true, // 开启babel缓存
                  cacheCompression: false, //关闭缓存文件压缩
                  plugins: ["@babel/plugin-transform-runtime"], // 减少代码体积
                }
              }
            ]
          },
          
        ]
      }
    ],
  },
  // 插件
  plugins: [
    new ESLintWebpackPlugin({
      // 指定检查文件的根目录
      context: path.resolve(__dirname, "../src"),
      exclude: 'node_modules', // 默认值
      cache: true,
      cacheLocation: path.resolve(
        __dirname,
        '../node_modules/.cache/eslintcache'
      ),
      threads, // 开启多进程和进程数量
    }),
    new HtmlWebpackPlugin({
      // 以 public/index.html 为模板创建文件
      // 新的html文件有两个特点：1. 内容和源文件一致 2. 自动引入打包生成的js等资源
      template: path.resolve(__dirname, "../public/index.html"),
    }),
    new MiniCssExtractPlugin({
      // 定义输出文件名和目录
      filename: "static/css/main.css",
    }),
    // new CssMinimizerPlugin(),
    // new TerserPlugin({
    //   parallel: threads // 开启多进程和设置进程数量
    // })
  ],
  optimization: {
    minimize: true,
    minimizer: [
      // css压缩也可以写到optimization.minimizer里面，效果一样的
      new CssMinimizerPlugin(),
      // 当生产模式会默认开启TerserPlugin，但是我们需要进行其他配置，就要重新写了
      new TerserPlugin({
        parallel: threads // 开启多进程
      }),
      
    // 压缩图片
    new ImageMinimizerPlugin({
      minimizer: {
        implementation: ImageMinimizerPlugin.imageminGenerate,
        options: {
          plugins: [
            ["gifsicle", { interlaced: true }],
            ["jpegtran", { progressive: true }],
            ["optipng", { optimizationLevel: 5 }],
            [
              "svgo",
              {
                plugins: [
                  "preset-default",
                  "prefixIds",
                  {
                    name: "sortAttrs",
                    params: {
                      xmlnsOrder: "alphabetical",
                    },
                  },
                ],
              },
            ],
          ],
        },
      },
    }),
    ],
  },
  // 模式
  mode: 'production',
  devtool: "source-map",
}